#include "yaml.h"
#include <iostream>
#include "db_conninfo.h"
#include "tables.h"
#include "dbtypes.h"
#include "opengauss/libpq-fe.h"
#include <unordered_map>
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <set>

extern std::string GetsShemanameTablenamesql;

// 判断a是否是b的前缀且b比a长
bool isRedundant(const std::string &a, const std::string &b)
{
    return a.length() <= b.length() && b.compare(0, a.length(), a) == 0;
}

// 自定义比较函数，按照字符串长度进行比较
bool compareByLength(const std::string &a, const std::string &b)
{
    return a.length() < b.length();
}

int compareindex(const std::vector<std::string> &data, std::vector<std::string> &st)
{

    std::vector<std::string> result;
    for (size_t i = 0; i < data.size(); ++i)
    {
        bool isRedundantRow = false;
        for (size_t j = 0; j < data.size(); ++j)
        {
            if (i != j && isRedundant(data[i], data[j]))
            {
                isRedundantRow = true;
                break;
            }
        }
        if (!isRedundantRow && find(result.begin(), result.end(), data[i]) == result.end())
        {
            result.push_back(data[i]);
        }
    }

    // 输出结果
    for (const auto &s : result)
    {
        st.push_back(s);
    }
    return 0;
}

std::string getsource(const char *location)
{
    YAML::Node config = YAML::LoadFile(location);
    std::string datasource;
    datasource.append("dbname=");
    datasource.append(config["diff"]["source"]["database"].as<std::string>());
    datasource.append(" port=");
    datasource.append(config["diff"]["source"]["port"].as<std::string>());
    datasource.append(" host=");
    datasource.append(config["diff"]["source"]["host"].as<std::string>());
    datasource.append(" application_name=libpq connect_timeout=5 sslmode=allow");
    datasource.append(" user=");
    datasource.append(config["diff"]["source"]["username"].as<std::string>());
    if (!config["diff"]["source"]["password"].IsNull())
    {
        datasource.append(" password=");
        datasource.append("'");
        datasource.append(config["diff"]["source"]["password"].as<std::string>());
        datasource.append("'");
    }
    return datasource;
}

static void
exit_nicely(PGconn *conn)
{
    PQfinish(conn);
    exit(1);
}

int QuerySettings(PGconn *conn, const char *sql, std::unordered_map<std::string, std::string> &configMap)
{
    int nFields;
    int i, j;

    // 执行查询语句
    PGresult *res = PQexec(conn, sql);
    if (PQresultStatus(res) != PGRES_TUPLES_OK)
    {
        fprintf(stderr, "查询失败: %s", PQerrorMessage(conn));
        PQclear(res);
        PQfinish(conn);
        return 1;
    }

    // 获取结果集中的行数
    int rows = PQntuples(res);
    nFields = PQnfields(res);
    /* 打印行 */
    char result[1024];
    for (j = 0; j < nFields; j++)
    {
        // 获取你需要的两个字段的列索引，假设需要 column2 和 column4
        int column_index1 = PQfnumber(res, "\"indexcolumn\"");
        int column_index2 = PQfnumber(res, "\"indexname\"");
        if (column_index1 == -1 || column_index2 == -1)
        {
            fprintf(stderr, "未找到指定的列\n");
            PQclear(res);
            PQfinish(conn);
            return 1;
        }

        // 遍历结果集，获取所需两个字段的值
        for (int i = 0; i < rows; i++)
        {
            const char *value1 = PQgetvalue(res, i, column_index1);
            const char *value2 = PQgetvalue(res, i, column_index2);
            // printf("第 %d 行: Schema 的值为 %s, Name 的值为 %s\n", i + 1, value1, value2);
            configMap[value2] = value1;
        }
    }

    // 释放结果集和关闭数据库连接
    PQclear(res);
    // PQfinish(conn);
    return 0;
}
/*
case
idx_field2:field1
idx_field1:field1

*/
int DuplicateColumn(const std::vector<std::string> &schemawithtablelist, const std::vector<std::string> &index_column, std::multimap<std::string, std::string> &DuplicateMap)
{
    std::map<std::string, bool> processed;
    auto it = DuplicateMap.begin();
    while (it != DuplicateMap.end())
    {
        const std::string &key = it->first;
        const std::string &value = it->second;
        if (processed.find(key) != processed.end())
        {
            // 输出重复的键值对信息
            // std::cout << "发现重复键: " << key << ", 值: " << value << std::endl;
            std::cout << "drop index " + schemawithtablelist[0] + "." + value + ";" << std::endl;
            // 已存在该key，删除当前元素
            it = DuplicateMap.erase(it);
        }
        else
        {
            // 首次出现该key，标记为已处理，移动到下一个元素
            processed[key] = true;
            ++it;
        }
    }
    if (DuplicateMap.size() >= 2)
    {

        std::cout << "============采用最左匹配原则-排查冗余索引============" << std::endl;
        std::vector<std::string> result;
        compareindex(index_column, result);
        for (const auto &st : result)
        {
            {
                // std::cout << st << std::endl;
                // 删除特定键的所有元素(删除需要的元素)
                DuplicateMap.erase(st);
            }
        }
        for (const auto &pair : DuplicateMap)
        {
            // 打印特定键的所有元素(不需要的元素)
            std::cout << "drop index " + schemawithtablelist[0] + "." + pair.second + ";" << std::endl;
        }
    }

    // std::cout << "\n处理后的multimap内容:" << std::endl;
    // for (const auto &pair : DuplicateMap)
    // {
    //     std::cout << pair.first << ": " << pair.second << std::endl;
    // }

    return EXIT_SUCCESS;
}
int ColumnNameDistinct(const std::vector<std::string> &schemawithtablelist, const std::vector<std::string> &index_column, std::unordered_map<std::string, std::string> &sroucemap)
{
    std::cout << "==============去重==========" << std::endl;
    // 构建反向映射（值 → 键集合）
    std::multimap<std::string, std::string> reverseMapci;
    for (const auto &pair : sroucemap)
    {
        reverseMapci.insert({pair.second, pair.first});
    }
    int status;
    status = DuplicateColumn(schemawithtablelist, index_column, reverseMapci);
    if (status != 0)
    {
        std::cerr << "有错误请排错: " << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

int GetIndexNameWithColumnName(const std::vector<std::string> &schemawithtablelist, std::unordered_map<std::string, std::string> &sroucemap)
{
    // 查询后判断map是否为空，不为空才能继续。索引名是key,列名是values
    if (!sroucemap.empty() && sroucemap.size() > 1)
    {
        std::cout << "schema名: " << schemawithtablelist[0] << "--" << "表名: " << schemawithtablelist[1] << std::endl;
        // 列名放入vector里面，
        std::vector<std::string> index_column;
        std::cout << "============修改前的字段与索引============" << std::endl;

        // 方便排序操作，也是为了下一步去重
        for (const auto &pair : sroucemap)
        {
            std::string s = pair.second;
            std::cout << pair.first << ":" << pair.second << std::endl;
            index_column.push_back(s);
        }
        // 排序
        std::sort(index_column.begin(), index_column.end(), compareByLength);
        std::cout << "============排序============" << std::endl;
        for (const auto &s : index_column)
        {
            std::cout << s << std::endl;
        }
        int status;
        status = ColumnNameDistinct(schemawithtablelist, index_column, sroucemap);
        if (status != 0)
        {
            std::cerr << "有错误请排错: " << std::endl;
            return EXIT_FAILURE;
        }
    }
    return EXIT_SUCCESS;
}

int main(int argc, char **argv)
{
    const char *location;
    if (argc > 1)
        location = argv[1];
    else
        location = "config.yaml";
    std::string srouce;
    srouce = getsource(location);
    // 创建srouce数据库连接
    PGconn *conn = createPGConnection(srouce);
    if (!conn)
    {
        return EXIT_FAILURE;
    }
    int status;
    int statusTablename;
    std::unordered_map<std::string, std::string> tableslist;
    statusTablename = GetsShemanameTablename(conn, GetsShemanameTablenamesql.c_str(), tableslist);
    if (statusTablename != 0)
    {
        std::cerr << "连接数据库出错: " << PQerrorMessage(conn) << std::endl;
        return EXIT_FAILURE;
    }

    std::vector<std::string> schemawithtable;
    for (const auto &pair : tableslist)
    {
        std::string s = pair.second;
        schemawithtable.push_back(pair.first);
    }
    for (const auto &s : schemawithtable)
    {
        std::vector<std::string> parts = split(s, '|');
        std::string sroucesql;
        sroucesql = buildSQLQuery(parts[0], parts[1]);
        std::unordered_map<std::string, std::string> sroucemap;
        status = QuerySettings(conn, sroucesql.c_str(), sroucemap);
        if (status != 0)
        {
            std::cerr << "连接数据库出错: " << PQerrorMessage(conn) << std::endl;
            return EXIT_FAILURE;
        }
        status = GetIndexNameWithColumnName(parts, sroucemap);
        if (status != 0)
        {
            std::cerr << "有错误请排错: " << std::endl;
            return EXIT_FAILURE;
        }
    }
    std::cout << "数据库类型: " << detectDatabaseType(conn) << std::endl;
    PQfinish(conn);
    return 0;
}

/*
-[ RECORD 5 ]----+-----------------------------------------
indexcolumn      | field2,field4
indexname        | idx_field2_field4
tablename        | your_table_name
Schema           | public
allpathindexname | public.idx_field2_field4
pg_size_pretty   | 8192 bytes
pg_relation_size | 8192

*/